package com.mg.plugin.drought.common;

import com.mg.model.Model;
import com.mg.plugin.drought.entity.StationData;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

public class PenmamCalculator {

    public static double caleEtref(StationData stationData, Model model) throws ParseException {
        if (stationData.getDay() == 0) {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            Date date = sdf.parse(stationData.getDate());
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            stationData.setDay(calendar.get(6));
        }
        model.OutputLog(Model.LogLevel.Debug, stationData.gettAvg() + ":" + stationData.gettMax() + ":" + stationData.gettMin() + ":" + stationData.getWindSpeed() + ":" + stationData.getDay() + ":" + stationData.getHumidity() + ":" + stationData.getSunshine() + ":" + stationData.getAlti() + ":" + stationData.getLat());
        return caleEtref(stationData.gettAvg(), stationData.gettMax(), stationData.gettMin(), stationData.getWindSpeed(), stationData.getDay(), stationData.getHumidity(), stationData.getSunshine(), stationData.getAlti(), stationData.getLat());
    }

    private static double caleEtref(StationData stationData) {
        return caleEtref(stationData.gettAvg(), stationData.gettMax(), stationData.gettMin(), stationData.getWindSpeed(), stationData.getDay(), stationData.getHumidity(), stationData.getSunshine(), stationData.getAlti(), stationData.getLat());
    }

    /**
     * ta平均温度，wd风速，day日序号，y总日数，hd相对湿度，rizhao总辐射，H高度，LAT纬度
     *
     * @param ta
     * @param tmax
     * @param tmin
     * @param wd
     * @param day
     * @param hd
     * @param rizhao
     * @param h
     * @param lat
     * @return
     */
    public static double caleEtref(double ta, double tmax, double tmin, double wd, double day, double hd, double rizhao, double h, double lat) {
        double y = 365;
        //湿度换算百分比
        if (hd > 1) {
            hd = hd / 100;
        }
        double pi = 3.141592654;
        double hu = 4.87 / (Math.log(67.8 * 10 - 5.42));
        wd = 4.87 / (Math.log(67.8 * 10 - 5.42)) * wd;
        double p = 101.3 * Math.pow(((273 + ta - 0.0065 * h) / (273 + ta)), 5.26);
        double lam = 2.501 - 0.002361 * ta;

        double r = 0.00163 * p / lam;
        double es = 0.611 * Math.exp(17.27 * ta / (237.3 + ta));
        double slop = 4098 * es / Math.pow((237.3 + ta), 2);
        double gsc = 0.0820;
        double dr = 1 + 0.033 * Math.cos(2 * day * pi / y);
        double solar = 0.409 * Math.sin(2 * day * pi / y - 1.39);
        lat = pi / 180 * lat;
        double x = Math.max(0.00001, 1 - Math.pow(Math.tan(lat), 2) * Math.pow(Math.tan(solar), 2));
        double ws = pi / 2 - Math.atan(-Math.tan(lat) * Math.tan(solar) / Math.sqrt(x));
        double ra = 24 * 60 / pi * gsc * dr * (ws * Math.sin(lat) * Math.sin(solar) + Math.cos(lat) * Math.cos(solar) * Math.sin(ws));
        double N = 24 / pi * ws;
        double rs = (0.25 + 0.50 * rizhao / N) * ra;
        double rns = 0.77 * rs;
        double rnl1 = 4.903 * Math.pow(10, -9) * (Math.pow(tmax + 273, 4) + Math.pow(tmin + 273, 4)) / 2 * (0.56 - 0.25 * Math.sqrt(es * hd));
        double rnl_xishu = 0.1 + 0.9 * rizhao / N;
        double rnl = rnl1 * rnl_xishu;
        double rn = rns - rnl;

        double etref = (0.408 * slop * rn + r * 900 / (ta + 273) * wd * (es - es * hd)) / (slop + r * (1 + 0.34 * wd));     //!潜在蒸散
//        double etair=(r*900/(ta+273)*wd*(es-es*hd))/(slop+r*(1+0.34*wd));//   !动力项
//        double etrad=(0.408*slop*rn)/(slop+r*(1+0.34*wd));// !辐射项
        return etref;
    }

    public static double caleCWDI(List<StationData> calcData, Calendar calendar, SimpleDateFormat sdf, Model model) throws ParseException {
        double kc = 0.6;
        double etref = 0.6;
        double totalRain = 0;
        double totalEtc0 = 0;
        for (StationData stationData : calcData) {
            if(stationData.getSunshine()>24){
                continue;
            }
            totalRain += stationData.getRain();
            kc = calcKc(stationData, calendar, sdf);
            etref = caleEtref(stationData, model);
            totalEtc0 += (etref * kc);
        }
        model.OutputLog(Model.LogLevel.Info, "caleCWDI:etref=" + etref + "totalEtc0=" + totalEtc0);
        return (1 - totalRain / totalEtc0) * 100;
    }

    public static double caleRHI(List<StationData> calcData, Calendar calendar, SimpleDateFormat sdf, Model model) throws ParseException {
        double kc = 0.6;
        double etref = 0.6;
        double totalRain = 0;
        double totalEtc0 = 0;
        for (StationData stationData : calcData) {
            if(stationData.getSunshine()>24){
                continue;
            }
            totalRain += stationData.getRain();
            kc = calcKc(stationData, calendar, sdf);
            etref = caleEtref(stationData, model);
            totalEtc0 += (etref * kc);
        }

        double result = ((totalRain - totalEtc0) / totalEtc0) * 100;
        model.OutputLog(Model.LogLevel.Info, "caleCWDI:result=" + result + "totalRain=" + totalRain + "totalEtc0=" + totalEtc0 + "size:" + calcData.size());
        return result;
    }

    /**
     * 计算KC值
     *
     * @param stationData
     * @param calendar
     * @param sdf
     * @return
     */
    private static double calcKc(StationData stationData, Calendar calendar, SimpleDateFormat sdf) throws ParseException {
        calendar.setTime(sdf.parse(stationData.getDate()));
        int month = calendar.get(Calendar.MONTH) + 1;
        int day = calendar.get(Calendar.DAY_OF_MONTH);
        int tenDays = getTenDays(day);
        switch (month) {
            case 4:
                return 0.2 + 0.1 * tenDays;
            case 5:
                return tenDays == 1 ? 0.5 : 0.6;
            case 6:
                return 0.6 + 0.1 * tenDays;
            case 7:
                return 1.0 + 0.1 * tenDays;
            case 8:
                return 1.3 - 0.1 * tenDays;
            case 9:
                return tenDays == 1 ? 1.0 : 1.0 - 0.1 * tenDays;
            default:
                return 0.6;
        }
    }

    private static int getTenDays(int day) {
        if (day <= 10) {
            return 1;
        }
        if (day <= 20) {
            return 2;
        }
        return 3;
    }

    public static void main(String[] args) {
        System.out.println(caleEtref(28.9,33.5,23.9,2.0,204,74.0,12.1,145.7,45.85));
        System.out.println(caleEtref(21.7,24.1,19.4,3.5,206,90.0,0.0,145.7,45.85));
        System.out.println(caleEtref(27.2,32.4,24.1,3.0,205,83.0,6.8,145.7,45.85));
        System.out.println(caleEtref(23.8,29.0,18.0,1.3,207,76.0,13.6,145.7,45.85));
        System.out.println(caleEtref(24.5,30.6,17.3,1.2,208,77.0,32766.0,145.7,45.85));
        System.out.println(caleEtref(27.5,32.0,22.0,3.2,210,73.0,12.7,145.7,45.85));
        System.out.println(caleEtref(25.6,30.5,20.1,2.3,209,75.0,13.7,145.7,45.85));
        System.out.println(caleEtref(28.5,33.0,23.4,3.1,200,87.0,4.1,145.7,45.85));
        System.out.println(caleEtref(26.4,30.8,24.0,2.9,201,88.0,0.0,145.7,45.85));
        System.out.println(caleEtref(26.8,32.2,24.5,3.1,202,90.0,7.1,145.7,45.85));
    }

}
